<?php
// $Id: Config.php 27 2010-11-16 12:49:54Z mjohnson60@gmail.com $

/**
 * Enter description here ...
 * 
 * @author Mark Phillip Johnson
 * @version 1.0
 * @copyright Copyright (c) 2010, markjohnson
 * @license http://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
 *
 */
class Config extends Object
{
	private static $instance = NULL;
	
	var $config = array();
	var $loaded = array();
	
	var $conf_path = NULL;
	
	var $base_url = NULL;
	var $base_path = NULL;
	var $base_root = NULL;
	
	var $db_url = 'mysql://username:password@localhost/databasename';
	
	var $cookie_domain = NULL;
	var $session_name = NULL;

	/**
	 * __construct()
	 * 
	 * Enter description here ...
	 * 
	 */
	public function __construct()
	{
		self::$instance = & $this;
	}

	/**
	 * getInstance()
	 * 
	 * Enter description here ...
	 * 
	 * @return Ambiguous
	 */
	public static function &getInstance()
	{
		if (!isset(self::$instance))
		{
			new Config();
		}
		
		return self::$instance;
	}

	/**
	 * @return the $base_url
	 */
	public static function baseUrl()
	{
		$_this = & Config::getInstance();
		return $_this->base_url;
	}

	/**
	 * @return the $base_path
	 */
	public static function basePath()
	{
		$_this = & Config::getInstance();
		return $_this->base_path;
	}

	/**
	 * @return the $base_path
	 */
	public static function dbUrl()
	{
		$_this = & Config::getInstance();
		return $_this->db_url;
	}

	/**
	 * @return the $cookie_domain
	 */
	public static function cookieDomain()
	{
		$_this = & Config::getInstance();
		return $_this->cookie_domain;
	}

	/**
	 * @return the $session_name
	 */
	public static function sessionName()
	{
		$_this = & Config::getInstance();
		return $_this->session_name;
	}

	/**
	 * Enter description here ...
	 */
	public static function init()
	{
		$_this = & Config::getInstance();
		if (isset($_SERVER['HTTP_HOST']))
		{
			$_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
			if (!valid_http_host($_SERVER['HTTP_HOST']))
			{
				Athena::httpStatusHeader(200, 'Bad Request');
				exit();
			}
		}
		else
		{
			$_SERVER['HTTP_HOST'] = '';
		}
		
		$db_url = NULL;
		$base_url = NULL;
		$cookie_domain = NULL;
		if (file_exists('./' . Config::confPath() . '/settings.inc'))
		{
			include_once ('./' . Config::confPath() . '/settings.inc');
			
			if (isset($db_url) && $db_url == 'mysql://username:password@localhost/databasename')
			{
				$_this->db_url = null;
			}
			else
			{
				$_this->db_url = isset($db_url) ? $db_url : NULL;
				unset($db_url);
			}
		}
		else
		{
			$_this->db_url = null;
		}
		
		if (isset($base_url))
		{
			$_this->base_url = $base_url;
			unset($base_url);
			
			$url_parts = parse_url($_this->base_url);
			if (!isset($url_parts['path']))
			{
				$url_parts['path'] = '';
			}
			
			$_this->base_path = $url_parts['path'] . '/';
			$_this->base_root = substr($_this->base_url, 0, strlen($_this->base_url) - strlen($url_parts['path']));
		}
		else
		{
			$_this->base_root = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
			
			$_this->base_url = $_this->base_root .= '://' . $_SERVER['HTTP_HOST'];
			
			if (($dir = trim(dirname($_SERVER['SCRIPT_NAME']), '\,/')) !== FALSE)
			{
				$_this->base_path = '/' . $dir;
				$_this->base_url .= $_this->base_path;
				$_this->base_path .= '/';
			}
			else
			{
				$_this->base_path = '/';
			}
		}
		
		if (isset($cookie_domain))
		{
			$_this->cookie_domain = $cookie_domain;
			$_this->session_name = $_this->cookie_domain;
		}
		else
		{
			list(, $_this->session_name) = explode('://', $_this->base_url, 2);
			
			if (!empty($_SERVER['HTTP_HOST']))
			{
				$_this->cookie_domain = check_plain($_SERVER['HTTP_HOST']);
				
				// Strip leading periods, www., and port numbers from cookie domain.
				$_this->cookie_domain = ltrim($_this->cookie_domain, '.');
				
				if (strpos($_this->cookie_domain, 'www.') === 0)
				{
					$_this->cookie_domain = substr($_this->cookie_domain, 4);
				}
				
				$_this->cookie_domain = explode(':', $_this->cookie_domain);
				$_this->cookie_domain = '.' . $_this->cookie_domain[0];
			}
		}
		
		// To prevent session cookies from being hijacked, a user can configure the
		// SSL version of their website to only transfer session cookies via SSL by
		// using PHP's session.cookie_secure setting. The browser will then use two
		// separate session cookies for the HTTPS and HTTP versions of the site. So we
		// must use different session identifiers for HTTPS and HTTP to prevent a
		// cookie collision.
		if (ini_get('session.cookie_secure'))
		{
			$_this->session_name .= 'SSL';
		}
		
		// Per RFC 2109, cookie domains must contain at least one dot other than the
		// first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
		if (count(explode('.', $_this->cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $_this->cookie_domain)))
		{
			ini_set('session.cookie_domain', $_this->cookie_domain);
		}
		
		session_name('SESS' . md5($_this->session_name));
	}

	/**
	 * Find the appropriate configuration directory.
	 *
	 * Try finding a matching configuration directory by stripping the website's
	 * hostname from left to right and pathname from right to left. The first
	 * configuration file found will be used; the remaining will ignored. If no
	 * configuration file is found, return a default value '$confdir/default'.
	 *
	 * Example for a fictitious site installed at
	 * http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched in
	 * the following directories:
	 *
	 * 1. $confdir/8080.www.drupal.org.mysite.test
	 * 2. $confdir/www.drupal.org.mysite.test
	 * 3. $confdir/drupal.org.mysite.test
	 * 4. $confdir/org.mysite.test
	 *
	 * 5. $confdir/8080.www.drupal.org.mysite
	 * 6. $confdir/www.drupal.org.mysite
	 * 7. $confdir/drupal.org.mysite
	 * 8. $confdir/org.mysite
	 *
	 * 9. $confdir/8080.www.drupal.org
	 * 10. $confdir/www.drupal.org
	 * 11. $confdir/drupal.org
	 * 12. $confdir/org
	 *
	 * 13. $confdir/default
	 *
	 * @param $require_settings
	 * Only configuration directories with an existing settings.php file
	 * will be recognized. Defaults to TRUE. During initial installation,
	 * this is set to FALSE so that Drupal can detect a matching directory,
	 * then create a new settings.php file in it.
	 * @param reset
	 * Force a full search for matching directories even if one had been
	 * found previously.
	 * @return
	 * The path of the matching directory.
	 */
	public static function confPath($require_settings = TRUE, $reset = FALSE)
	{
		$_this = & Config::getInstance();
		if (isset($_this->conf_path) && !$reset)
		{
			return $_this->conf_path;
		}
		
		$confdir = 'sites';
		
		$uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']);
		$server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
		for ($i = count($uri) - 1; $i > 0; $i--)
		{
			for ($j = count($server); $j > 0; $j--)
			{
				$dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
				if (file_exists("$confdir/$dir/settings.inc") || (!$require_settings && file_exists("$confdir/$dir")))
				{
					$_this->conf_path = "$confdir/$dir";
					return $_this->conf_path;
				}
			}
		}
		
		$_this->conf_path = "$confdir/default";
		
		return $_this->conf_path;
	}

	/**
	 * Enter description here ...
	 * @param unknown_type $file
	 * @param unknown_type $useSections
	 * @param unknown_type $failGracefully
	 * @return boolean
	 */
	public function load($file = '', $useSections = FALSE, $failGracefully = FALSE)
	{
		$file = (empty($file) ? 'config' : str_replace('.php', '', $file));
		
		if (in_array($file, $this->loaded))
		{
			return TRUE;
		}
		
		if (!file_exists(Config::confPath() . '/config/' . $file . '.php'))
		{
			if ($failGracefully === TRUE)
			{
				return FALSE;
			}
			
			Athena::setMessage('The configuration file ' . $file . '.php does not exist.', 'error');
		}
		
		$config = array();
		include_once (Config::confPath() . '/config/' . $file . '.php');
		
		if (empty($config) || !is_array($config))
		{
			if ($failGracefully === TRUE)
			{
				return FALSE;
			}
			
			Athena::setMessage('Your configuration file ' . $file . '.php is improperly formatted.', 'error');
		}
		
		if ($useSections === TRUE)
		{
			if (isset($this->config[$file]))
			{
				$this->config[$file] = array_merge($this->config, $config);
			}
			else
			{
				$this->config[$file] = $config;
			}
		}
		else
		{
			$this->config = array_merge($this->config, $config);
		}
		
		$this->loaded[] = $file;
		unset($config);
		
		return TRUE;
	}
}
